package com.example.supernote.data.network.config

import android.net.Uri
import android.util.Base64
import java.nio.charset.StandardCharsets
import java.util.SortedSet
import java.util.TreeSet
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import kotlin.random.Random

private fun generateRandomString(len: Int): String {
    val chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    val sb: StringBuilder = StringBuilder(len)
    for (i in 0 until len) sb.append(chars[Random.nextInt(chars.length)])
    return sb.toString()
}

private fun generateCanonicalQueryString(queryParams: String?): String {
    if (queryParams.isNullOrEmpty()) {
        return ""
    }

    val params = HashMap<String, String>()
    val param = queryParams.split("&".toRegex()).dropLastWhile { it.isEmpty() }
        .toTypedArray()
    for (item in param) {
        val pair = item.split("=".toRegex()).dropLastWhile { it.isEmpty() }
            .toTypedArray()
        if (pair.size == 2) {
            params[pair[0]] = pair[1]
        } else {
            params[pair[0]] = ""
        }
    }
    val keys: SortedSet<String> = TreeSet(params.keys)
    val sb = StringBuilder()
    var first = true
    for (key in keys) {
        if (!first) {
            sb.append("&")
        }
        val item: String = Uri.encode(key, "utf8") + "=" + Uri.encode(
            params[key], "utf8"
        )
        sb.append(item)
        first = false
    }

    return sb.toString()
}

private fun generateSignature(appKey: String, signingString: String): String {
    try {
        val mac = Mac.getInstance("HmacSHA256")
        val secret = SecretKeySpec(appKey.toByteArray(StandardCharsets.UTF_8), mac.algorithm)
        mac.init(secret)
        return Base64.encodeToString(mac.doFinal(signingString.toByteArray()), Base64.NO_WRAP)
    } catch (err: Exception) {
        return ""
    }
}

fun generateAuthHeaders(
    appId: String,
    appKey: String,
    method: String,
    uri: String,
    queryParams: String
): Map<String, String> {

    val nonce = generateRandomString(8)
    val timestamp = (System.currentTimeMillis() / 1000).toString()
    val canonicalQueryString = generateCanonicalQueryString(queryParams)
    val signedHeadersString = String.format(
        "x-ai-gateway-app-id:%s\nx-ai-gateway-timestamp:%s\nx-ai-gateway-nonce:%s".trimIndent(),
        appId,
        timestamp,
        nonce
    )

    val fields = arrayOf(
        method,
        uri,
        canonicalQueryString,
        appId,
        timestamp,
        signedHeadersString
    )
    val buf = java.lang.StringBuilder(fields.size * 16)
    for (i in fields.indices) {
        if (i > 0) {
            buf.append("\n")
        }
        buf.append(fields[i])
    }

    val headers = mapOf(
        "X-AI-GATEWAY-APP-ID" to appId,
        "X-AI-GATEWAY-TIMESTAMP" to timestamp,
        "X-AI-GATEWAY-NONCE" to nonce,
        "X-AI-GATEWAY-SIGNED-HEADERS" to "x-ai-gateway-app-id;x-ai-gateway-timestamp;x-ai-gateway-nonce",
        "X-AI-GATEWAY-SIGNATURE" to generateSignature(appKey, buf.toString()),
    )
    return headers
}